package com.zhuzhe.blog.article.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zhuzhe.blog.article.mapper.ArticleThumhupMapper;
import com.zhuzhe.blog.article.requestDto.*;
import com.zhuzhe.blog.article.responseVo.ArticlePageListVo;
import com.zhuzhe.blog.article.responseVo.ArticleVo;
import com.zhuzhe.blog.base.JsonData;
import com.zhuzhe.blog.base.ResponseData;
import com.zhuzhe.blog.category.responseVo.LabellistVo;
import com.zhuzhe.blog.convert.Convert;
import com.zhuzhe.blog.article.entity.Article;
import com.zhuzhe.blog.article.mapper.ArticleMapper;
import com.zhuzhe.blog.article.service.IArticleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhuzhe.blog.article.entity.ArticleThumhup;
import com.zhuzhe.blog.enums.ArticleStatusEnum;
import com.zhuzhe.blog.feign.label.IFeignLabelController;
import com.zhuzhe.blog.utils.GetIpUtil;
import com.zhuzhe.blog.utils.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * <p>
 * 文章信息表 服务实现类
 * </p>
 *
 * @author u53
 * @since 2020-10-05
 */
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements IArticleService {

    @Autowired
    private ArticleThumhupMapper articleThumhupMapper;

    private static final String REDIS_ARTICLE = "_article_";

    @Autowired
    private IFeignLabelController feignLabelController;

    //装配redis
    @Autowired
    private RedisUtil redisUtil;

    @Override
    public ResponseData<IPage<ArticlePageListVo>> queryPage(ArticleSerachDto articleDto) {

        QueryWrapper<Article> wrapper = new QueryWrapper<>();
        //文章查询条件 标题 和 状态
        wrapper.like(StringUtils.isNotEmpty(articleDto.getTitle()),Article.TITLE,articleDto.getTitle())
        .eq(articleDto.getStatus()!=null
                && articleDto.getStatus()!=-1,Article.STATUS,articleDto.getStatus());
        IPage<Article> articleIPage = baseMapper.selectPage(articleDto.getPage(),wrapper);
        //声明返回值参数
        IPage<ArticlePageListVo> articlePageList = new Page<ArticlePageListVo>();
        Convert.convertType(articleIPage,articlePageList);
        //响应参数内部结合
        List<ArticlePageListVo> articlePageLists2 = new ArrayList<>();
        //封装返回参数
        for (Article article:articleIPage.getRecords()){
            ArticlePageListVo artclePage = new ArticlePageListVo();
            //将值进行copy
            Convert.convertType(article,artclePage);
            articlePageLists2.add(artclePage);
        }
        articlePageList.setRecords(articlePageLists2);
        return JsonData.success(articlePageList);

    }

    @Override
    public ResponseData<ArticleVo> findArticleAndLabelById(String articleId , String userId) {
        ArticleVo articleVo = baseMapper.findArticleAndLabelById(articleId);
        if(null == articleVo){
            return JsonData.fail("无文章详情信息");
        }
        //远程调用接口 查询 标签信息
        List<LabellistVo> labellistVos = feignLabelController.getLabelListByIds(articleVo.getLabelIds());
        if (null != labellistVos){
            articleVo.setLabelList(labellistVos);
        }
        //查看当前文章用户是否点赞 返回前端做按钮事件
        if (StringUtils.isEmpty(userId)){
            articleVo.setThumhupBool(true);
        }else {
            QueryWrapper<ArticleThumhup> queryWrapper = new QueryWrapper();
            queryWrapper.eq(ArticleThumhup.ARTICLE_ID,articleId)
                    .eq(ArticleThumhup.USER_ID,userId);
            ArticleThumhup articleThumhup = articleThumhupMapper.selectOne(queryWrapper);
            if (articleThumhup == null){
                articleVo.setThumhupBool(true);
            }else{
                articleVo.setThumhupBool(false);
            }
        }
        return JsonData.success(articleVo);
    }
    @Transactional // 事务管理 失败后回滚操作
    @Override
    public ResponseData<String> updateOrSave(ArticleDto articleDto) {
        //copy对象
        Article article = new Article();
        Convert.convertType(articleDto,article);
        // 1. 如果id不为空，则是更新操作
        if(StringUtils.isNotEmpty(article.getId())) {
            // 更新：先删除文章中间表数据，再新增到中间表
            baseMapper.deleteArticleLabel(article.getId());
            // 更新：将更新时间设置当前时间
            article.setUpdateDate(new Date());
        }
        // 如果文章是ispublic不公开的，直接审核通过(status)，否则等待审核
        if(article.getIspublic() == 0) { // 0：不公开，1：公开
            article.setStatus(ArticleStatusEnum.SUCCESS.getCode()); // 0: 已删除, 1:未审核，2:审核通过，3：审核未通过
        }else {
            article.setStatus(ArticleStatusEnum.WAIT.getCode());
        }
        // 更新或保存文章信息（新增数据后，会将这条新增数据的主键id值放到id属性中）
        super.saveOrUpdate(article);

        // 新增标签数据到文章标签中间表中
        if(CollectionUtils.isNotEmpty(articleDto.getLabelIds())) {
            baseMapper.saveArticleLabel(article.getId(), articleDto.getLabelIds());
        }
        // 返回文章id
        return JsonData.success(article.getId());
    }

    @Override
    public ResponseData<String> updateStatus(String id, ArticleStatusEnum statusEnum) {
        // 先查询当前数据库的数据
        Article article = baseMapper.selectById(id);
        // 将状态值 更新
        article.setStatus(statusEnum.getCode());
        article.setUpdateDate(new Date());
        baseMapper.updateById(article);
        return JsonData.success(article.getId());
    }

    @Override
    public ResponseData<IPage<ArticlePageListVo>> findListByUserId(ArticleUserDto articleUserDto) {
        if(StringUtils.isEmpty(articleUserDto.getUserId())) {
            return JsonData.fail("无效用户信息");
        }
        QueryWrapper<Article> wrapper = new QueryWrapper();
        wrapper.eq(Article.USER_ID, articleUserDto.getUserId());
        if(articleUserDto.getIsPublic() != null) {
            // ispublic 字段名都是小写
            wrapper.eq(Article.ISPUBLIC, articleUserDto.getIsPublic());
        }
        // 排序
        wrapper.orderByDesc(Article.UPDATE_DATE);
        IPage<Article> page = baseMapper.selectPage(articleUserDto.getPage(), wrapper);
        //声明返回值参数
        IPage<ArticlePageListVo> articlePageList = new Page<ArticlePageListVo>();
        Convert.convertType(page,articlePageList);
        //响应参数内部结合
        List<ArticlePageListVo> articlePageLists2 = new ArrayList<>();
        //封装返回参数
        for (Article article:page.getRecords()){
            ArticlePageListVo artclePage = new ArticlePageListVo();
            //将值进行copy
            Convert.convertType(article,artclePage);
            articlePageLists2.add(artclePage);
        }
        articlePageList.setRecords(articlePageLists2);
        return JsonData.success(articlePageList);
    }

    @Override
    @Transactional
    public ResponseData<String> updateThumhup(ArticleThumhupDto articleThumhupDto) {
        //传入点赞数是否合法
        if(articleThumhupDto.getCount() != -1 && articleThumhupDto.getCount() != 1) {
            return JsonData.fail("无效操作");
        }

        //传入文章id是否存在
        if(StringUtils.isEmpty(articleThumhupDto.getArticleId())) {
            return JsonData.fail("无效操作");
        }

        // 查询这篇文章现有数据，查询到后，将点赞数进行更新
        Article article = baseMapper.selectById(articleThumhupDto.getArticleId());
        if(article == null) {
            return JsonData.fail("文章不存在");
        }

        //如该文章点赞数 无法取消点赞
        if(article.getThumhup() <= 0 && articleThumhupDto.getCount() == -1) {
            return JsonData.fail("无效操作");
        }

        //先查询中间表数据
        QueryWrapper<ArticleThumhup> queryWrapper = new QueryWrapper();
        queryWrapper.eq(ArticleThumhup.ARTICLE_ID,articleThumhupDto.getArticleId())
                .eq(ArticleThumhup.USER_ID,articleThumhupDto.getUserId());
        ArticleThumhup articleThumhup = articleThumhupMapper.selectOne(queryWrapper);

        //判断传入是否为 1 如果传入 1 查看关联表中是否存在数据,如果存在数据则无法继续点赞
        if (articleThumhupDto.getCount() == 1){
            if (articleThumhup != null){
                return JsonData.fail("该文章已经点赞过");
            }
            ArticleThumhup  articleThumhupa = new ArticleThumhup();
            articleThumhupa.setArticleId(articleThumhupDto.getArticleId());
            articleThumhupa.setUserId(articleThumhupDto.getUserId());
            articleThumhupMapper.insert(articleThumhupa);
        }

        //判断传入是否为 -1 如果传入 -1 说明是取消点赞删除关联表中数据
        if (articleThumhupDto.getCount() == -1){
            if (null == articleThumhup){
                return JsonData.fail("未赞过该文章无法取消点赞");
            }
            articleThumhupMapper.deleteById(articleThumhup.getId());
        }

        // 更新点赞数
        article.setThumhup( article.getThumhup() + articleThumhupDto.getCount() );
        baseMapper.updateById(article);
        return JsonData.success(article.getId());
    }



    @Override
    public ResponseData<String> updateViewCount(String id, HttpServletRequest request) {

        String key = GetIpUtil.getIp(request)+REDIS_ARTICLE+id;
        //查询该ip 是否 访问过 此文章
        if(redisUtil.hasKey(key)){
            return JsonData.success();
        }
        if(StringUtils.isEmpty(id)) {
            return JsonData.fail("无效操作");
        }
        Article article = baseMapper.selectById(id);
        if(article == null){
            return JsonData.fail("文章不存在");
        }
        //浏览记录存入redis 时长 5分钟 ,5分钟之内不该ip 访问不累加浏览次数
        redisUtil.set(key,null,60*5);
        article.setViewCount( article.getViewCount() + 1 );

        baseMapper.updateById(article);
        return JsonData.success(article.getId());
    }

    @Override
    public ResponseData<IPage<ArticlePageListVo>> findListByLabelIdOrCategoryId(ArticleListDto articleListDto) {
        IPage<Article> page = new Page<>();
        IPage<ArticlePageListVo> articlePageListVoIPage = new Page<>();
        List<String> labelsId = new ArrayList<>();
        // 远程调用接口 查询分类下的标签id
        if (null != articleListDto.getCategoryId()){
            labelsId = feignLabelController.getLabelListByIds(articleListDto.getCategoryId());
        }else{
            if (null != articleListDto.getLabelId()) {
                labelsId.add(articleListDto.getLabelId());
            }
        }
        page = baseMapper.findListByLabelIdOrCategoryId(articleListDto.getPage(),labelsId);
        Convert.convertType(page,articlePageListVoIPage);
        articlePageListVoIPage.setRecords(Convert.convertList(page.getRecords(),ArticlePageListVo.class));
        return JsonData.success(articlePageListVoIPage);
    }

    @Override
    public ResponseData<Map> selectMonthArticleTotal() {
        List<Map<String, Object>> maps = baseMapper.selectMonthArticleTotal();
        // 将年月提取到集合中
        List<Object> yearMonthList = new ArrayList<>();
        // 将每个月的文章数提取到集合中
        List<Object> articleTotalList = new ArrayList<>();

        for(Map<String, Object> map: maps) {
            yearMonthList.add ( map.get("year_month") );
            articleTotalList.add( map.get("total") );
        }
        // 封装响应的data数据
        Map<String, Object> data = new HashMap<>();
        data.put("yearMonthList", yearMonthList);
        data.put("articleTotalList", articleTotalList);
        return JsonData.success(data);
    }

    @Override
    public ResponseData<Integer> getArticleTotal() {
        QueryWrapper<Article> wrapper = new QueryWrapper<>();
        // 状态是审核通过
        wrapper.eq("status", ArticleStatusEnum.SUCCESS.getCode());
        // 公开
        wrapper.eq("ispublic", 1);
        Integer total = baseMapper.selectCount(wrapper);
        return JsonData.success(total);
    }

    @Override
    public ResponseData<Map> selectCategoryTotal() {

        //TODO 视图部分暂未修改
        List<Map<String, Object>> maps = baseMapper.selectCategoryTotal();

        // 将分类名称单独提取到集合中
        List<Object> nameList = new ArrayList<>();
        for(Map<String, Object> map: maps) {
            nameList.add( map.get("name") );
        }

        // 封装响应数据
        Map<String, Object> data = new HashMap<>();
        data.put("nameAndValueList", maps);
        data.put("nameList", nameList);

        return JsonData.success(data);
    }

}
